from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from django.http import HttpResponse
from user.models import *
import re
import random
import string
import redis
from django.contrib.auth.hashers import make_password, check_password
from captcha.image import ImageCaptcha
import jwt
from shop.settings import SECRET_KEY
from django.db.models import Q


# Create your views here.

# 强制登录的装饰器
def check_login(func):
    def wrap(*agrs, **kwargs):
        request = agrs[1]

        token = request.headers.get("Token")
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms="HS256")
        except Exception as e:
            print(e)
            return Response({
                "code": 403,
                "msg": "登录失败"
            })

        user_id = payload["user_id"]
        request.user_id = user_id

        return func(*agrs, **kwargs)

    return wrap


class RegView(APIView):
    def post(self, request):
        """注册用户"""

        # 接收参数
        username = request.data.get("username")
        password = request.data.get("password")
        password2 = request.data.get("password2")
        mobile = request.data.get("mobile")
        code = request.data.get("code")
        uuid = request.data.get("uuid")

        # 校验验证码。 判断一下用户输入的验证码 和 图片上面展示的一样不一样
        rds = redis.Redis(host="127.0.0.1", db=2)
        print("code_%s" % uuid)
        code_byte = rds.get("code_%s" % uuid)  # bytes类型 或者是  None类型
        if code_byte is None:
            return Response({
                "code": 400,
                "msg": "验证码已过期"
            })

        if code.upper() != code_byte.decode().upper():
            return Response({
                "code": 400,
                "msg": "验证码错误"
            })

        # 校验参数
        if password != password2:
            return Response({
                "code": 400,
                "msg": "密码不一致"
            })

        # 校验手机号
        # 手机号正则
        rule = "^1[3-9]\d{9}$"
        if not re.findall(rule, mobile):
            return Response({
                "code": 400,
                "msg": "手机号格式错误"
            })

        # 用户名要求：首字母必须是大小写字母，不能是数字。后面可以是字母、数字和下划线的组合.最少6位，最长16位
        username_rule = "^[a-zA-Z][a-zA-Z0-9_]{5,15}$"
        if not re.findall(username_rule, username):
            return Response({
                "code": 400,
                "msg": "用户名格式错误"
            })

        # 限制用户名唯一：在插入数据之前，该用户名不存在与数据库

        user_info = UserModel.objects.filter(username=username).first()  # 查询到以后，返回的是这条数据对象。如果查询不到，返回的是 None
        if user_info:
            return Response({
                "code": 400,
                "msg": "用户名已存在"
            })

        user_info2 = UserModel.objects.filter(mobile=mobile).first()  # 查询到以后，返回的是这条数据对象。如果查询不到，返回的是 None
        if user_info2:
            return Response({
                "code": 400,
                "msg": "手机号已存在"
            })

        # 密码加密
        password_ = make_password(password)  # 加密后的数据

        # 增删改查
        try:
            UserModel.objects.create(
                username=username,
                password=password_,
                mobile=mobile,
            )
        except Exception as e:
            print(e)
            return Response({
                "code": 400,
                "msg": "注册失败"
            })

        # 返回响应
        return Response({
            "code": 200,
            "msg": "注册成功"
        })


class CheckUserName(APIView):
    def get(self, request):
        """校验用户名"""
        # 接收参数
        username = request.query_params.get("name")

        # 用户名要求：首字母必须是大小写字母，不能是数字。后面可以是字母、数字和下划线的组合.最少6位，最长16位
        username_rule = "^[a-zA-Z][a-zA-Z0-9_]{5,15}$"
        if not re.findall(username_rule, username):
            return Response({
                "code": 400,
                "msg": "用户名格式错误"
            })

        # 限制用户名唯一：在插入数据之前，该用户名不存在与数据库

        user_info = UserModel.objects.filter(username=username).first()  # 查询到以后，返回的是这条数据对象。如果查询不到，返回的是 None
        if user_info:
            return Response({
                "code": 400,
                "msg": "用户名已存在"
            })

        return Response({
            "code": 200,
            "msg": "校验通过"
        })


class CodeView(APIView):
    def get(self, request, uuid):
        # 1. 生成随机字符串
        code = "".join(random.sample(string.ascii_letters + string.digits, 4))

        # 2. 把字符串变成图片  Captcha
        # 2.1  实例化验证码生成器
        i = ImageCaptcha()
        # 2.2  调用验证码生成器的生成方法，来创建验证码
        img = i.generate(code)

        # 3. 使用Redis来存 uuid和验证码的对应关系
        rds = redis.Redis(host="127.0.0.1", port=6379, db=2)
        rds.set("code_%s" % uuid, code, ex=300)
        rds.close()

        # 4. 返回图片
        return HttpResponse(img, content_type="image/png")


class LoginView(APIView):
    def post(self, request):
        # username = request.data.get("username")
        account = request.data.get("account")  # 账号，可能是用户名，也可能时手机号
        password = request.data.get("password")
        # Q  ,或 或 并 条件的时候使用

        user_info = UserModel.objects.filter(Q(username=account) | Q(mobile=account)).first()
        if user_info is None:
            return Response({
                "code": 400,
                "msg": "用户不存在"
            })
        # 第一个参数 明文密码  第二个参数 加密后的密码. 返回布尔
        if not check_password(password, user_info.password):
            return Response({
                "code": 400,
                "msg": "密码错误"
            })

        # 发布令牌
        token = jwt.encode({
            "user_id": user_info.id,
            "username": user_info.username
        }, SECRET_KEY)

        # 返回响应
        return Response({
            "code": 200,
            "msg": "登录成功",
            "data": {
                "token": token,
                "user": user_info.username
            }
        })


class UserInfoView(APIView):

    @check_login
    def get(self, request):
        """获取用户的个人信息。包括用户名，手机号，收货地址"""
        user_id = request.user_id

        user_info = UserModel.objects.filter(id=user_id).first()
        if not user_info:
            return Response({
                "code": 400,
                "msg": "出错啦"
            })

        return Response({
            "code": 200,
            "msg": "获取成功",
            "data": {
                "username": user_info.username,
                "phone": user_info.mobile,
                "addrs": [{
                    "id": i.id,
                    "receiver": i.name,
                    "receiver_mobile": i.mobile,
                    "receiver_addr": i.addr,
                    "is_default": i.is_default,
                } for i in user_info.addressmodel_set.all()],
            }
        })

    @check_login
    def put(self, request):
        mobile = request.data.get("phone")
        addr = request.data["addrs"]
        user_id = request.user_id

        # 验证手机号规则
        rule = "^1[3-9]\d{9}$"
        if not re.findall(rule, mobile):
            return Response({
                "code": 400,
                "msg": "手机号格式错误"
            })

        user_info = UserModel.objects.filter(id=user_id).first()
        if not user_info:
            return Response({
                "code": 400,
                "msg": "用户信息不存在"
            })

        if mobile != user_info.mobile:
            u = UserModel.objects.filter(mobile=mobile).first()
            if u:
                return Response({
                    "code": 400,
                    "msg": "手机号重复"
                })

        user_info.mobile = mobile
        user_info.save()

        # 修改收货地址
        for i in addr:
            temp_addr = AddressModel.objects.filter(id=i["id"]).first()
            temp_addr.name = i["receiver"]
            temp_addr.mobile = i["receiver_mobile"]
            temp_addr.addr = i["receiver_addr"]
            temp_addr.is_default = i["is_default"]

            if i["is_default"]:
                # 把之前的设置为非默认地址
                AddressModel.objects.filter(user_id=user_id).update(is_default=False)

            temp_addr.save()

        return Response({
            "code": 200,
            "msg": "修改成功"
        })


class AddressView(APIView):

    @check_login
    def post(self, request):
        """添加收货地址"""
        name = request.data.get("receiver")
        mobile = request.data.get("receive_mobile")
        addr = request.data.get("receive_addr")
        is_default = request.data.get("is_default")
        user_id = request.user_id

        # 校验参数
        if not all([name, mobile, addr]):
            return Response({
                "code": 400,
                "msg": "参数不完整"
            })

        # 如果要添加的地址是默认地址。把当前用户的其他地址全部设置成非默认地址。
        if is_default:
            AddressModel.objects.filter(user_id=user_id).update(is_default=False)

        # 增删改查
        try:
            addr_info = AddressModel.objects.create(
                name=name,
                mobile=mobile,
                addr=addr,
                is_default=is_default,
                user_id=user_id,
            )
        except Exception as e:
            print(e)
            return Response({
                "code": 400,
                "msg": "收货地址添加失败"
            })

        return Response({
            "code": 200,
            "msg": "收货地址添加成功",
            "data": {
                "id": addr_info.id,
                "receiver": addr_info.name,
                "receiver_mobile": addr_info.mobile,
                "receiver_addr": addr_info.addr,
                "is_default": is_default
            }
        })

    @check_login
    def delete(self, request):
        id = request.query_params.get("id")
        user_id = request.user_id

        addr_info = AddressModel.objects.filter(id=id).first()
        if not addr_info:
            return Response({
                "code": 400,
                "msg": "用户地址不存在"
            })

        if addr_info.user_id != user_id:
            return Response({
                "code": 400,
                "msg": "无权删除"
            })

        try:
            addr_info.delete()
        except Exception as e:
            print(e)
            return Response({
                "code": 400,
                "msg": "删除失败"
            })

        return Response({
            "code": 200,
            "msg": "删除成功"
        })


class PasswordView(APIView):
    @check_login
    def put(self, request):
        o_password = request.data.get("o_password")
        pwd = request.data.get("pwd")
        pwd2 = request.data.get("pwd2")
        user_id = request.user_id

        # 校验参数
        if pwd != pwd2:
            return Response({
                "code": 400,
                "msg": "两次密码不一致"
            })

        # 判断原始密码对不对
        user_info = UserModel.objects.filter(id=user_id).first()
        if not user_info:
            return Response({
                "code": 400,
                "msg": "用户不存在"
            })

        if not check_password(o_password, user_info.password):
            return Response({
                "code": 400,
                "msg": "密码错误"
            })

        # 密码校验通过，修改密码
        pwd_ = make_password(pwd)
        user_info.password = pwd_
        user_info.save()

        return Response({
            "code": 200,
            "msg": "修改成功"
        })
